﻿using sentry.Model;
using sentry.Tool;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using System.Diagnostics;
using System.Threading;

namespace sentry
{
    /// <summary>
    /// 任务管理
    /// </summary>
    public class TaskManager
    {
        #region 任务列表
        /// <summary>
        /// 任务列表
        /// </summary>
        private List<TaskInfo> _taskList = null;
        #endregion

        #region 锁
        /// <summary>
        /// 锁
        /// </summary>
        private object _lockObj = null;
        #endregion

        #region 日志
        /// <summary>
        /// 日志
        /// </summary>
        private Log _log;
        #endregion

        #region 实例
        private static TaskManager _instance;

        public static TaskManager Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new TaskManager();
                }
                return _instance;
            }
        }

        private TaskManager()
        {
            _lockObj = new object();
            _log = App.Services.GetService<Log>();
            _taskList = new List<TaskInfo>();
        }
        #endregion

        #region 公共

        #region 读取任务配置
        /// <summary>
        /// 读取任务配置
        /// </summary>
        public int Reload()
        {
            int count = 0;
            List<FileInfo> iniFileList = new List<FileInfo>();
            string path = App.TaskDir;
            DirectoryInfo directory = new DirectoryInfo(path);
            FileInfo[] files = directory.GetFiles();
            if (files != null && files.Length > 0)
            {
                foreach (FileInfo fileInfo in files)
                {
                    string ext = Path.GetExtension(fileInfo.Name);
                    if (!string.IsNullOrEmpty(ext))
                    {
                        if (ext.ToLower() == ".ini")
                        {
                            iniFileList.Add(fileInfo);
                        }
                    }
                }
            }

            lock (_lockObj)
            {
                _taskList = new List<TaskInfo>();
                foreach (FileInfo file in iniFileList)
                {
                    TaskInfo taskInfo = ReadIniInfo(file.FullName);
                    _taskList.Add(taskInfo);
                    count++;
                }
            }
            return count;
        }
        #endregion

        #region 更新任务配置信息
        /// <summary>
        /// 更新任务配置信息
        /// </summary>
        /// <returns></returns>
        public int Update()
        {
            int count = 0;
            List<FileInfo> iniFileList = new List<FileInfo>();
            string path = App.TaskDir;
            DirectoryInfo directory = new DirectoryInfo(path);
            FileInfo[] files = directory.GetFiles();
            if (files != null && files.Length > 0)
            {
                foreach (FileInfo fileInfo in files)
                {
                    string ext = Path.GetExtension(fileInfo.Name);
                    if (!string.IsNullOrEmpty(ext))
                    {
                        if (ext.ToLower() == ".ini")
                        {
                            iniFileList.Add(fileInfo);
                        }
                    }
                }
            }
            lock (_lockObj)
            {
                foreach (FileInfo file in iniFileList)
                {
                    string name = Path.GetFileNameWithoutExtension(file.Name).ToLower();
                    if (_taskList.Where(t => t.Name == name).FirstOrDefault() == null)
                    {
                        TaskInfo taskInfo = ReadIniInfo(file.FullName);
                        _taskList.Add(taskInfo);
                        count++;
                    }
                }
            }

            return count;
        }
        #endregion

        #region 获取任务状态
        /// <summary>
        /// 获取任务状态
        /// </summary>
        /// <returns></returns>
        public List<sentrygrpc.TaskStatus> GetStatus()
        {
            List<sentrygrpc.TaskStatus> result = new List<sentrygrpc.TaskStatus>();
            lock (_lockObj)
            {
                if (_taskList != null && _taskList.Count > 0)
                {
                    foreach (TaskInfo task in _taskList)
                    {
                        sentrygrpc.TaskStatus ts = new sentrygrpc.TaskStatus();
                        ts.Name = task.Name;
                        if (task.Status == 1)
                        {
                            ts.Pid = task.Pid.ToString();
                            ts.Type = sentrygrpc.StatusType.Running;
                            TimeSpan timeSpan = DateTime.Now - task.RunTime;
                            string uptime = "";
                            int day = (int)Math.Floor(timeSpan.TotalDays);
                            if (day > 0)
                            {
                                uptime = day.ToString() + " days,";
                            }
                            uptime += string.Format("{0:D2}", timeSpan.Hours) + ":" + string.Format("{0:D2}", timeSpan.Minutes) + ":" + string.Format("{0:D2}", timeSpan.Seconds);
                            ts.Uptime = uptime;
                        }
                        else
                        {
                            ts.Type = sentrygrpc.StatusType.Stop;
                            ts.Pid = "-";
                            ts.Uptime = "-";
                        }
                        result.Add(ts);
                    }
                }
            }
            return result;
        }
        #endregion

        #region 启动所有任务
        /// <summary>
        /// 启动所有任务
        /// </summary>
        /// <returns></returns>
        public int StartAll()
        {
            try
            {
                int count = 0;
                lock (_lockObj)
                {
                    if (_taskList != null && _taskList.Count > 0)
                    {
                        foreach (TaskInfo task in _taskList)
                        {
                            if (task.Status == 0)
                            {
                                Process process = task.RunTask();
                                if (process.Id > 0)
                                {
                                    task.Pid = process.Id;
                                    task.Task = process;
                                    task.Status = 1;
                                    task.RunTime = DateTime.Now;
                                    task.ErrorRunCount = 0;
                                    count++;
                                }
                                //todo 启动任务
                            }
                        }
                    }
                }
                return count;
            }
            catch (Exception ex)
            {
                _log.WriteException(ex);
                return 0;
            }
        }
        #endregion

        #region 启动任务
        /// <summary>
        /// 启动任务
        /// </summary>
        /// <param name="name">任务名称</param>
        /// <returns></returns>
        public bool Start(string name)
        {
            try
            {
                bool isok = false;
                lock (_lockObj)
                {
                    string tempName = name.ToLower().Trim();
                    if (_taskList != null && _taskList.Count > 0)
                    {
                        foreach (TaskInfo task in _taskList)
                        {
                            if (task.Status == 0 && task.Name == tempName)
                            {
                                Process process = task.RunTask();
                                if (process.Id > 0)
                                {
                                    task.Pid = process.Id;
                                    task.Task = process;
                                    task.Status = 1;
                                    task.RunTime = DateTime.Now;
                                    task.ErrorRunCount = 0;
                                    isok = true;
                                }
                                //todo 启动任务
                                break;
                            }
                        }
                    }
                }
                return isok;
            }
            catch (Exception ex)
            {
                _log.WriteException(ex);
                return false;
            }
        }
        #endregion

        #region 停止所有任务
        /// <summary>
        /// 停止所有任务
        /// </summary>
        /// <returns></returns>
        public int StopAll()
        {
            try
            {
                int count = 0;
                lock (_lockObj)
                {
                    if (_taskList != null && _taskList.Count > 0)
                    {
                        foreach (TaskInfo task in _taskList)
                        {
                            if (task.Status == 1)
                            {
                                task.Kill();
                                task.Status = 0;
                                task.RunTime = DateTime.MinValue;
                                task.Pid = 0;
                                task.Task = null;
                                count++;
                                //todo 停止任务
                            }
                        }
                    }
                }
                return count;
            }
            catch (Exception ex)
            {
                _log.WriteException(ex);
                return 0;
            }
        }
        #endregion

        #region 停止任务
        /// <summary>
        /// 停止任务
        /// </summary>
        /// <param name="name">任务名称</param>
        /// <returns></returns>
        public bool Stop(string name)
        {
            try
            {
                bool isok = false;
                lock (_lockObj)
                {
                    string tempName = name.ToLower().Trim();
                    if (_taskList != null && _taskList.Count > 0)
                    {
                        foreach (TaskInfo task in _taskList)
                        {
                            if (task.Status == 1 && task.Name == tempName)
                            {
                                task.Kill();
                                task.Status = 0;
                                task.RunTime = DateTime.MinValue;
                                task.Pid = 0;
                                task.Task = null;
                                isok = true;
                                //todo 停止任务
                                break;
                            }
                        }
                    }
                }
                return isok;
            }
            catch (Exception ex)
            {
                _log.WriteException(ex);
                return false;
            }
        }
        #endregion

        #region 监测死掉的任务并重启
        /// <summary>
        /// 监测死掉的任务并重启
        /// 只重启30次
        /// </summary>
        public void CheckDeadTaskAndRun()
        {
            try
            {
                lock (_lockObj)
                {
                    if (_taskList != null && _taskList.Count > 0)
                    {
                        foreach (TaskInfo task in _taskList)
                        {
                            if (task.Status == 1)
                            {

                                Process process = task.Task;
                                if (process.HasExited)
                                {
                                    if (task.ErrorRunCount < 30)
                                    {
                                        Process process2 = task.RunTask();
                                        if (process2.Id > 0)
                                        {
                                            TimeSpan ts = DateTime.Now - task.ErrorRunTime;
                                            if (ts.TotalSeconds > 60)
                                            {
                                                task.ErrorRunCount = 0;
                                            }
                                            if (task.ErrorRunCount == 0)
                                            {
                                                task.ErrorRunTime = DateTime.Now;
                                            }
                                            task.ErrorRunCount += 1;
                                            task.Pid = process2.Id;
                                            task.Task = process2;
                                            task.Status = 1;
                                            task.RunTime = DateTime.Now;
                                        }
                                    }
                                    else
                                    {
                                        task.Status = 0;
                                        task.Pid = 0;
                                        task.Task = null;
                                    }
                                }
                                //todo 启动任务
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _log.WriteException(ex);
            }
        }
        #endregion

        #region 自动启动
        /// <summary>
        /// 自动启动
        /// </summary>
        public void AutoStart()
        {
            try
            {
                int count = 0;
                lock (_lockObj)
                {
                    if (_taskList != null && _taskList.Count > 0)
                    {
                        foreach (TaskInfo task in _taskList)
                        {
                            if (task.AutoStart && task.Status == 0)
                            {
                                Process process = task.RunTask();
                                if (process.Id > 0)
                                {
                                    task.Pid = process.Id;
                                    task.Task = process;
                                    task.Status = 1;
                                    task.RunTime = DateTime.Now;
                                    task.ErrorRunCount = 0;
                                    count++;
                                }
                                //todo 启动任务
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _log.WriteException(ex);
            }
        }
        #endregion

        #region 定时重启任务
        /// <summary>
        /// 定时重启任务
        /// </summary>
        public void RunTimingRestartTask()
        {
            try
            {
                lock (_lockObj)
                {
                    if (_taskList != null && _taskList.Count > 0)
                    {
                        foreach (TaskInfo task in _taskList)
                        {
                            Thread thread = new Thread(new ParameterizedThreadStart(AutoRestartTask));
                            thread.IsBackground = true;
                            thread.Start(task);
                            
                            //todo 启动任务
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _log.WriteException(ex);
            }
        }
        #endregion

        #endregion

        #region 私有

        #region 读取配置信息
        /// <summary>
        /// 读取配置信息
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private static TaskInfo ReadIniInfo(string fileName)
        {
            string section = "program";

            TaskInfo taskInfo = new TaskInfo();
            //名称
            taskInfo.Name = Path.GetFileNameWithoutExtension(fileName);
            if (!string.IsNullOrEmpty(taskInfo.Name))
            {
                taskInfo.Name = taskInfo.Name.ToLower().Trim();
            }
            //运行目录
            taskInfo.Directory = IniHelper.ReadConfig<string>(fileName, section, "directory");
            if (!string.IsNullOrEmpty(taskInfo.Directory))
            {
                taskInfo.Directory = taskInfo.Directory.ToLower().Trim();
            }
            //执行命令
            taskInfo.Command = IniHelper.ReadConfig<string>(fileName, section, "command");
            if (!string.IsNullOrEmpty(taskInfo.Command))
            {
                taskInfo.Command = taskInfo.Command.ToLower().Trim();
            }
            //是否自启动
            taskInfo.AutoStart = IniHelper.ReadConfig<bool>(fileName, section, "autostart");
            //是否自动重启
            taskInfo.AutoRestart = IniHelper.ReadConfig<bool>(fileName, section, "autorestart");
            //自动重启时间
            taskInfo.RestartTime = IniHelper.ReadConfig<string>(fileName, section, "restart_time");
            if (!string.IsNullOrEmpty(taskInfo.RestartTime))
            {
                taskInfo.RestartTime = taskInfo.RestartTime.ToLower().Trim();
            }
            //错误日志文件
            taskInfo.StderrLogfile = IniHelper.ReadConfig<string>(fileName, section, "stderr_logfile");
            if (!string.IsNullOrEmpty(taskInfo.StderrLogfile))
            {
                taskInfo.StderrLogfile = taskInfo.StderrLogfile.ToLower().Trim();
            }
            //输出日志文件
            taskInfo.StdoutLogfile = IniHelper.ReadConfig<string>(fileName, section, "stdout_logfile");
            if (!string.IsNullOrEmpty(taskInfo.StdoutLogfile))
            {
                taskInfo.StdoutLogfile = taskInfo.StdoutLogfile.ToLower().Trim();
            }
            return taskInfo;
        }
        #endregion

        #region 自动重启任务
        /// <summary>
        /// 自动重启任务
        /// </summary>
        /// <param name="obj"></param>
        private void AutoRestartTask(object obj)
        {
            if (obj != null && obj is TaskInfo)
            {
                TaskInfo task = (TaskInfo)obj;
                if (task.AutoRestart)
                {
                    if (task.GetIsAutoRestartTime())
                    {
                        _log.WriteDebug($"自动重启{task.Name}开始");
                        if (task.Status == 1)
                        {
                            task.Kill();
                            task.Status = 0;
                            task.RunTime = DateTime.MinValue;
                            task.Pid = 0;
                            task.Task = null;
                        }

                        Thread.Sleep(5000);

                        Process process = task.RunTask();
                        if (process.Id > 0)
                        {
                            task.Pid = process.Id;
                            task.Task = process;
                            task.Status = 1;
                            task.RunTime = DateTime.Now;
                            task.ErrorRunCount = 0;
                        }
                        _log.WriteDebug($"自动重启{task.Name}完成");
                    }
                }
            }
        } 
        #endregion

        #endregion
    }
}
